package rmi.farted;


import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

import javax.swing.DefaultListModel;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel;

/**
 * <p>Title: GuiBox </p>
 * <p>Description: Text-mode client, connecting to server via RMI</p>
 * @version 1.0, Okt 2010
 * @author J. Schoch
 */

public class FartEd extends JFrame implements WindowListener, ActionListener, KeyListener, ClientInterpreter {
	private static final long serialVersionUID = 1L;

	// globals
	private final String ich = "FartEd ";
	private String servername = null;
	private boolean debug = true;
	
	// Clientspezifisch
	private int userID = 0;
	
	// Menu
	private JMenuBar menubalken;
	private JMenu menudatei, menuserver, menuhelp;	// menus
	private JMenuItem quit;	// menuitem file
	private JMenuItem verbinden; // menuitem connect
	private JMenuItem about;	// menuitem help
	
	// Editor
	private JTextArea ausgabe;
	
	// UserList
	private DefaultListModel userListModel;
	private JList userList;
	private JScrollPane userScrollPane;
	
	// Server
	private ServerInterpreter server = null;

	// Konstruktor
	public FartEd (String[] args) {
		if (System.getProperty("os.name").contains("Mac")) {
			System.setProperty("apple.laf.useScreenMenuBar", "true");	// damit beim Mac das Menu in der Statusanzeige erscheint
		}
		setTitle(ich);
		say("FartEd started!");
		this.setLayout(new BorderLayout());
		
		// start connection directly with arguments
		if (args.length > 0) {
			connectToServer(args[0]);
		}
		
		createMenu();
		createFileList();
		createUserList();
		createStatus();
		createEditor();
		
		// examples
		userListModel.addElement("Jonas");
		userListModel.addElement("Fabian");
		userListModel.addElement("Andy");
		userListModel.addElement("Matthias");
		userListModel.addElement("David");
		
		//organize window
		this.addWindowListener(this);
		this.setSize(600,500);
		this.setVisible(true);
		ausgabe.requestFocus();
	} // Constructor


	// Connector ====================================================================

	/*
	 * baut verbindung auf zum server. gleichzeitig wird der client beim 
	 * server registriert, sodass der client vom server mittels push methods
	 * angeregt werden kann.
	 */
	private void connectToServer(String name) {
		String erfolg;

		// Dialog falls keine angabe zum Server
		if (name == null) {
			ModalDialog serverwahl = new ModalDialog(this,"Please enter URL of RMI-Server");
			serverwahl.setAnswer("rmi://localhost/FartServ");	// Preset!
			serverwahl.setVisible(true);
			name = serverwahl.getAnswer();
		}

		// Server-Objekt instantiieren
		String problem = "";
		if (name != null) {
			try {
				UnicastRemoteObject.exportObject(this);	// sehr wichtig!!!
				Object newborn = Naming.lookup(name);
				if (newborn instanceof ServerInterpreter) {
					server = (ServerInterpreter) newborn;
					servername = name;
					userID = server.registerClient(this);	// register itself at the server
					if (userID == 0){
						problem = "(Client konnte nicht registriert werden)";
					}
				} else {
					problem = "("+name+".class does not implement required interface.)";
				}
            }
			catch(RemoteException er) {
				say("fail to register client: " + er.toString());
				problem = "(fail to register client for " + name + ")";
			}
			catch(Exception e) {
				say("Lookup fail: " + e.toString());
				problem = "(Lookup failure for "+name+")";
            }
		}

		// bei Erfolg!!
		if (server != null) {
			if (servername == name) {erfolg = "connected to "+name;}
			else {erfolg = "still connected to "+servername + " " + problem;}
		}
		else {
			erfolg = "not connected "+problem;
		}

		setTitle(ich + erfolg);
	} // connectToServer



// Interpreter ==================================================================

	// call servermethod from Interface
	
	private void interpretKeyPressed(char keyID) {
		if (server != null) {
			try {
				// TODO: calc this following values!
				int hashValueText = 0;
				int keyPosRow = 0;
				int keyPosCol = 0;
				server.interpretKeyPressed(userID, hashValueText, keyID, keyPosRow, keyPosCol);
			} catch (Exception e) {
				say("Remote Problem "+e.toString());
			}
		}
	}
	
	// methode, welche vom server aufgerufen wird
	public void printChar(char keyID, int keyPosRow, int keyPosCol) throws RemoteException {
		ausgabe.append(String.valueOf(keyID));
	}

// Action Listener --------------------------------------------------
	public void actionPerformed (ActionEvent e){

		//----- Server-Operationen ...
		if (e.getSource() == verbinden) {connectToServer(null);}
		
		//----- File-Operationen ...
		if (e.getSource() == quit) {
			say("Exit FartEd!");
			System.exit(0);
		}

		//----- Help-Operationen ...
		if (e.getSource() == about) {aboutBox();}
	}
	

// Key Listener -------------------------------------------------
	public void keyPressed(KeyEvent e) {
		char pressedChar = e.getKeyChar();
		
		if (Character.isWhitespace(pressedChar) || Character.isLetterOrDigit(pressedChar)) {
			interpretKeyPressed(e.getKeyChar());	// send the keycode to the server
		}
	}


	public void keyReleased(KeyEvent e) {
		
	}


	public void keyTyped(KeyEvent e) {
		
	}

// Window Listeners --------------------------------------------------
	public void windowClosing(WindowEvent e){
		say("Quit FartEd.");
		System.exit(0);
	}
	//----- die folgenden M�SSEN "implementiert" werden
	public void windowOpened(WindowEvent e){ }
	public void windowClosed(WindowEvent e){ }
	public void windowIconified(WindowEvent e){ }
	public void windowDeiconified(WindowEvent e){ }
	public void windowActivated(WindowEvent e){ }
	public void windowDeactivated(WindowEvent e){ }

	

	
// -------------------------------------------------------------------
// create UI ---------------------------------------------------------
// -------------------------------------------------------------------	
	public void createMenu() {
		// organize menubar
		menubalken = new JMenuBar();
		setJMenuBar(menubalken);
		
		menubalken.add(menudatei = new JMenu("File"));
		menudatei.add(quit = new JMenuItem("Quit"));
		quit.addActionListener(this);
		
		menubalken.add(menuserver = new JMenu("Server"));
		menuserver.add(verbinden = new JMenuItem("Connect ..."));
		verbinden.setAccelerator(KeyStroke.getKeyStroke('C', InputEvent.META_MASK | InputEvent.SHIFT_MASK));
		verbinden.addActionListener(this);
		
		menubalken.add(menuhelp = new JMenu("Help"));
		menuhelp.add(about = new JMenuItem("About"));
		about.addActionListener(this);
	}
	
	
	
	public void createFileList() {
		
	}
	
	
	
	public void createUserList() {
		userListModel = new DefaultListModel();			// setze Model f�r Listeneintr�ge
		userList = new JList(userListModel);			// setze Liste
		userList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);	// nur ein User ausw�hlbar
		userScrollPane = new JScrollPane();				// erstelle Scrollzeugs
		userScrollPane.getViewport().setView(userList);	// setze Liste in ScrollPane
		this.add(userScrollPane, BorderLayout.EAST);	
	}
	
	
	
	public void createStatus() {
		
	}
	
	
	
	public void createEditor() {
		// organize textarea
		ausgabe = new JTextArea();
		this.add(ausgabe, BorderLayout.CENTER);
		//ausgabe.setBackground(new Color(150,255,150));
		ausgabe.setFont(new Font("Courier",Font.ITALIC,14));
		ausgabe.setEditable(true);
		ausgabe.addKeyListener(this);	// add Text-Area to KeyListener
	}
	

// Hilfsbetriebe ==================================================
	public static void main (String[] args) {
		new FartEd(args); // Eine Art von BootStrap
	}
	
	public void say(String s) {
		if (debug) System.out.println(s);
	}

// Help-Operationen ==================================================

	public void aboutBox() {
		DisplayBox db = new DisplayBox(this,"About "+ich);
		db.appendln("A client-server setup using simple RMI");
		db.appendln("(FartEd, ZHAW, Oktober 2010)");
		db.setSize(new Dimension(300,100));
		db.setVisible(true);
	}

} //class GuiBox
